﻿using System;
using System.Data.Linq;
using System.Linq;
using Domain;
using Munimji.Controller;
using NUnit.Framework;


namespace IntegrationTests
{
    [TestFixture]
    public class ControllerIntegrationTest
    {
        private Controller controller;
        private RepositoryDataContext dataContext;
        private Profile testProfie;
        private Account testAccount;
        private Account anotherTestAccount;

        [SetUp]
        public void SetUp()
        {
            controller = new Controller();
            dataContext = new RepositoryDataContext();
            testProfie = new Profile() {Title = "TestProfile", Username = "Test", Password = "Test"};
            testAccount = new Account() {Title = "TestAccount", IsInFlowAccount = true,IsOutFlowAccount = true};
            anotherTestAccount = new Account() { Title = "AnotherTestAccount", IsInFlowAccount = true, IsOutFlowAccount = true };
        }

        [Test]
        public void ShouldCreateNewProfile()
        {

            controller.CreateProfile(testProfie.Title, testProfie.Username, testProfie.Password);

            var matchedProfile = (from p in dataContext.Profiles where p.Title == testProfie.Title select p).First();
          
            Assert.IsNotNull(matchedProfile);
            Assert.AreEqual(testProfie.Title,matchedProfile.Title);
            Assert.AreEqual(testProfie.Username,matchedProfile.Username);
            Assert.AreEqual(testProfie.Password,matchedProfile.Password);
        }

        [Test]
        public void ShouldCreateAccout()
        {
            var profile = controller.CreateProfile(testProfie.Title, testProfie.Username, testProfie.Password);
            controller.CreateAccount(testAccount.Title, testAccount.IsInFlowAccount, testAccount.IsOutFlowAccount,profile);
            
            Assert.IsNotNull(profile.Accounts);
            Assert.IsTrue(profile.Accounts.Count>0);
            Assert.AreEqual(testAccount.Title,profile.Accounts[0].Title);
        
        }

        [Test]
        public void ShouldCreateNewTransaction()
        {
            var profile = controller.CreateProfile(testProfie.Title, testProfie.Username, testProfie.Password);
            var fromAccount = controller.CreateAccount(testAccount.Title, testAccount.IsInFlowAccount,
                                                       testAccount.IsOutFlowAccount, profile);
            var toAccount = controller.CreateAccount(anotherTestAccount.Title, anotherTestAccount.IsInFlowAccount,
                                                     anotherTestAccount.IsOutFlowAccount, profile);
            double amount = 100;
            controller.TransferAmount(profile, fromAccount, toAccount, amount,DateTime.Now,"Test transfer");

            Assert.IsNotNull(profile.Transactions);
            Assert.IsTrue(profile.Transactions.Count == 1);

            Assert.AreEqual(1,fromAccount.Debits.Count);
            Assert.AreEqual(0,fromAccount.Credits.Count);
            
            Assert.AreEqual(0,toAccount.Debits.Count);
            Assert.AreEqual(1,toAccount.Credits.Count);
            
            Assert.AreEqual(amount,profile.Transactions[0].Amount);
            Assert.AreEqual(-100,fromAccount.Balance);
            Assert.AreEqual(100,toAccount.Balance);

        }

        [Test]
        public void ShouldDeleteProfile()
        {
            var profile = controller.CreateProfile(testProfie.Title, testProfie.Username, testProfie.Password);
            controller.DeleteProfile(profile);

            var profiles = (from p in dataContext.Profiles where p.Title == testProfie.Title select p).ToList<Profile>();
            Assert.IsTrue(profiles.Count==0);
        }

        [Test]
        public void ShouldDeleteTransaction()
        {
            var profile = controller.CreateProfile(testProfie.Title, testProfie.Username, testProfie.Password);
            var fromAccount = controller.CreateAccount(testAccount.Title, testAccount.IsInFlowAccount,
                                                       testAccount.IsOutFlowAccount, profile);
            var toAccount = controller.CreateAccount(anotherTestAccount.Title, anotherTestAccount.IsInFlowAccount,
                                                     anotherTestAccount.IsOutFlowAccount, profile);
            double amount = 100;
            var transfer = controller.TransferAmount(profile, fromAccount, toAccount, amount, DateTime.Now, "Test transfer");
            controller.DeleteTransaction(transfer);
            Assert.IsTrue(profile.Transactions.Count == 0);
        }

        [Test]
        public void ShouldDeleteAccount()
        {
            var profile = controller.CreateProfile(testProfie.Title, testProfie.Username, testProfie.Password);
            var account = controller.CreateAccount(testAccount.Title, testAccount.IsInFlowAccount, testAccount.IsOutFlowAccount, profile);
            controller.DeleteAccount(account);
            Assert.IsTrue(profile.Accounts.Count==0);
        }

        [Test]
        public void ShouldUpdateChanges()
        {
            var profile = controller.CreateProfile(testProfie.Title, testProfie.Username, testProfie.Password);
            var newtitle = "NewTitle";
            profile.Title = newtitle;
            controller.UpdateChanges();

            var profiles = (from p in dataContext.Profiles where p.Id == profile.Id select p).ToList<Profile>();
            profile = profiles[0];

            Assert.IsTrue(profile.Title == newtitle);

            profile.Title = testProfie.Title;
            controller.UpdateChanges();
        }

        [TearDown]
        public void TearDown()
        {
            var profiles = (from p in dataContext.Profiles where p.Title == testProfie.Title select p).ToList<Profile>();
            foreach (var profile in profiles)
            {
                dataContext.Profiles.DeleteOnSubmit(profile);
            }
            dataContext.SubmitChanges(ConflictMode.FailOnFirstConflict);

        }
    }
}
